package com.hsqyz.esp32_led.netty.server;

import com.hsqyz.esp32_led.netty.channel.SocketChannelInitialize;
import com.hsqyz.esp32_led.netty.listener.NettyCloseFutureListener;
import com.hsqyz.esp32_led.netty.listener.NettyStartFutureListener;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * ESP32 Netty服务器
 * 
 * 该类负责启动和管理Netty服务器，主要功能包括：
 * 1. 服务器配置：设置服务器参数，如端口、缓冲区大小等
 * 2. 服务器启动：初始化并启动Netty服务器
 * 3. 服务器关闭：优雅地关闭服务器，释放资源
 * 4. 生命周期管理：通过Spring的生命周期注解管理服务器状态
 * 
 * 使用@ConfigurationProperties注解支持从配置文件读取服务器配置
 */
@Slf4j
@Component
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "netty")
public class Esp32NettyServer implements Runnable {

    /**
     * 通道初始化器，用于配置新连接的通道
     */
    private final SocketChannelInitialize socketChannelInitialize;

    /**
     * 服务器启动事件监听器
     */
    private final NettyStartFutureListener nettyStartFutureListener;

    /**
     * 服务器关闭事件监听器
     */
    private final NettyCloseFutureListener nettyCloseFutureListener;

    /**
     * 服务器端口号
     */
    @Setter
    private Integer serverPort;

    /**
     * 主事件循环组，用于处理连接请求
     */
    private EventLoopGroup mainGroup = null;

    /**
     * 工作事件循环组，用于处理已连接通道的I/O事件
     */
    private EventLoopGroup workerGroup = null;

    /**
     * 服务器启动方法
     * 
     * 在Spring容器初始化完成后调用，启动Netty服务器
     */
    @PostConstruct
    public void start() {
        log.info("Esp32通讯服务开始启动（port: {}）", serverPort);
        Thread server = new Thread(this);
        server.start();
    }

    /**
     * 服务器关闭方法
     * 
     * 在Spring容器关闭前调用，优雅地关闭Netty服务器
     */
    @PreDestroy
    public void stop() {
        log.info("Esp32通讯服务开始关闭(port: {})", serverPort);
        if (mainGroup != null) {
            mainGroup.shutdownGracefully();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
    }

    /**
     * 服务器运行方法
     * 
     * 实现Runnable接口，负责服务器的具体启动流程：
     * 1. 创建事件循环组
     * 2. 配置服务器引导程序
     * 3. 绑定端口并启动服务器
     * 4. 等待服务器关闭
     * 5. 清理资源
     */
    @Override
    public void run() {
        // 初始化事件循环组
        mainGroup = new NioEventLoopGroup(1);  // 主线程组，只使用一个线程
        workerGroup = new NioEventLoopGroup();  // 工作线程组，使用默认线程数

        // 创建服务器引导程序
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        // 配置服务器参数
        serverBootstrap.group(mainGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                // 设置连接队列大小
                .option(ChannelOption.SO_BACKLOG, 16 * 1024 * 1024)
                // 启用TCP Keep-Alive
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                // 设置接收缓冲区大小
                .childOption(ChannelOption.SO_RCVBUF, 16 * 1024 * 1024)
                // 设置发送缓冲区大小
                .childOption(ChannelOption.SO_SNDBUF, 16 * 1024 * 1024)
                // 设置通道初始化器
                .childHandler(socketChannelInitialize);

        try {
            // 绑定端口并启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(serverPort).addListener(nettyStartFutureListener).sync();
            if (channelFuture.isSuccess()) {
                log.info("netty start success port = {}", serverPort);
            }
            // 等待服务器关闭
            channelFuture.channel().closeFuture().addListener(nettyCloseFutureListener).sync();
        } catch (InterruptedException e) {
            log.error("netty server start fail {}", e.getMessage());
        } finally {
            // 优雅关闭事件循环组
            mainGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
